# -*- coding: utf-8 -*-
from selenium import webdriver
from time import sleep
import requests
# from options.chrome_options import Options
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait

from common.verify_code import SlideVerificationCode
from common.video import video_record, on_press
from log.log import Logger

from selenium.webdriver.common.by import By
import zipfile,mysql.connector


def open_browser(browser_type):
    try:
        if browser_type == 'CHR':
            # Logger().log().info('正常启动浏览器中......')
            print('正在正常启动浏览器中...')
            driver = webdriver.Chrome()
        else:
            driver = getattr(webdriver, browser_type)()
    except Exception as e:
        # Logger().log().info("输入浏览器类型错误，默认调用谷歌浏览器，错误信息{}".format(e))
        driver = webdriver.Chrome()

    return driver
class Web:

    # def __init__(self, browser_type):
    #     self.driver = open_browser(browser_type)
    def __init__(self):
        self.driver = None
        self.video_flag = False
        # from ddt.excel_ddt import conf
        # self.flag = conf.flag

        # 这两种设置都进行才有效
        # self.driver.set_page_load_timeout(20)# 设置页面加载超时
        # self.driver.set_script_timeout(10)# 设置页面异步js执行超时
        self.log = Logger().log()
        # 连接数据库，当前未配置
        self.ccon = mysql.connector.connect(
            host='localhost',  # localhost
            user='root',  # root
            password='admin',  # admin
            database='test'  # test
        )
        self.cmd = self.ccon.cursor()

    def video_record(self):
        from PIL import ImageGrab
        import numpy as np
        import cv2
        import datetime
        # video_flag = video_flag
        # global flag  # 停止标志位
        # flag = False
        """
        屏幕录制！
        :return:
        """
        name = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
        # vid = cv2.VideoCapture('./2022-06-13 15-33-12.avi')
        # video_width = int(vid.get(3))
        # video_height = int(vid.get(4))
        p = ImageGrab.grab()  # 获得当前屏幕
        a, b = p.size  # 获得当前屏幕的大小
        print("开始录制")
        fourcc = cv2.VideoWriter_fourcc(*'XVID')  # 编码格式
        video = cv2.VideoWriter('%s.mp4v' % name, fourcc, 10, (a, b))  # 输出文件命名为test.mp4,帧率为16，可以自己设置
        while True:
            im = ImageGrab.grab()
            imm = cv2.cvtColor(np.array(im), cv2.COLOR_RGB2BGR)  # 转为opencv的BGR格式
            video.write(imm)
            if self.video_flag:
                print("录制结束！")
                break
        video.release()

    def on_press(self):
        """
        键盘监听事件！！！
        :param key:
        :return:
        """
        # print(key)
        # global video_flag
        # if key == keyboard.Key.esc:
        self.video_flag = True
        print("stop monitor！")
        return False  # 返回False，键盘监听结束！

    def open_browser(self, br='gc'):
        if br == 'gc':

            # th = threading.Thread(target=video_record, args=[self.flag])
            # th.start()
            # video_record(self.flag)
            # import threading
            # th = threading.Thread(target=self.video_record)
            # th.start()
            from options.chrome_options import Options
            self.log.info('正在正常启动谷歌浏览器...')
            self.driver = webdriver.Chrome(options=Options().options_conf())
            # self.driver.set_page_load_timeout(20)  # 设置页面加载超时
            # self.driver.set_script_timeout(10)  # 设置页面异步js执行超时

        elif br == 'ff':
            from options.firefox_options import Options
            self.log.info('正在启动火狐浏览器...')
            self.driver = webdriver.Firefox(options=Options().options_conf())

        elif br == 'ie':
            from options.ie_options import Options
            self.log.info('正在启动ie浏览器...')
            self.driver = webdriver.Ie(options=Options().options_conf())
            self.driver.maximize_window()

        elif br == 'edge':
            from options.edge_options import Options
            self.log.info('正在启动edge浏览器...')
            from msedge.selenium_tools import Edge, EdgeOptions
            self.driver = Edge(executable_path=r'D:\python\MicrosoftWebDriver.exe', options=Options().options_conf())
            # self.driver = webdriver.Edge()该方法默认驱动位置，不需要指定，但是无配置参数

        else:
            self.log.info("暂不支持该浏览器，请再次添加代码")
        # self.driver.maximize_window()
        # self.driver.set_window_size(1396, 1100)
        # print("窗口大小是：{}".format(self.driver.get_window_size()))

        # 通过修改webdriver属性为False,一定是再访问系统之前，在启动浏览器之后的第一步执行这个，当页面反爬虫时用
        # self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
        #     "source": """
        #     Object.defineProperty(navigator,'webdriver', {
        #        get: () => false
        #     })
        # """
        # })
    def get_url(self, url=None):
        # self.driver.set_page_load_timeout(10)# 设置页面加载超时
        # self.driver.set_script_timeout(10)# 设置页面异步js执行超时

        try:
            self.driver.get(url)
        except Exception as e:
            self.log.info("访问url异常，异常信息：\n{}".format(e))
            self.log.info("也有可能是因为打开页面超时：\n{}".format(e))
            # 设置一个超时时间，如果页面加载超过了指定时间，手工终止页面，相当于用手点击浏览器的 X 按钮，让页面停止加载。
            self.driver.execute_script('window.stop()')
            self.log.info("访问url异常，异常信息：\n{}".format(e))
        # self.driver.execute_script("document.body.style.zoom='0.67'")

    def findEle(self, loc=''):
        ele = None
        self.ele = None
        try:
            if loc.startswith('xpath='):
                ele = self.driver.find_element_by_xpath(loc[loc.find('=')+1:])
            elif loc.startswith('id='):
                ele = self.driver.find_element_by_id(loc[loc.find('=')+1:])
            elif loc.startswith('name='):
                ele = self.driver.find_element_by_name(loc[loc.find('=')+1:])
            elif loc.startswith('tag_name='):
                # 在一个页面中，相同的标签有很多，所以一般不用标签来定位
                ele = self.driver.find_element_by_tag_name(loc[loc.find('=')+1:])
            elif loc.startswith('link_text='):
                ele = self.driver.find_element_by_link_text(loc[loc.find('=')+1:])
            elif loc.startswith('partial_link_text='):
                ele = self.driver.find_element_by_partial_link_text(loc[loc.find('=')+1:])
            elif loc.startswith('css_selector='):
                ele = self.driver.find_element_by_css_selector(loc[loc.find('=')+1:])
            else:
                ele = self.driver.find_element_by_xpath(loc)

            self.driver.execute_script("arguments[0].style.background='#ff3bff'", ele)
        except Exception as e:
            self.log.info("定位元素出现异常，异常信息：{}".format(e))
            # 可以看到更详细的错误信息
            # import traceback
            # traceback.print_exc()
        self.ele = ele
        return ele

    def findEles(self, loc=''):
        ele = None
        self.ele = None
        try:
            if loc.startswith('xpath='):
                ele = self.driver.find_elements_by_xpath(loc[loc.find('=')+1:])
            elif loc.startswith('id='):
                ele = self.driver.find_elements_by_id(loc[loc.find('=')+1:])
            elif loc.startswith('name='):
                ele = self.driver.find_elements_by_name(loc[loc.find('=')+1:])
            elif loc.startswith('tag_name='):
                ele = self.driver.find_elements_by_tag_name(loc[loc.find('=')+1:])
            elif loc.startswith('link_text='):
                ele = self.driver.find_elements_by_link_text(loc[loc.find('=')+1:])
            elif loc.startswith('partial_link_text='):
                ele = self.driver.find_elements_by_partial_link_text(loc[loc.find('=')+1:])
            elif loc.startswith('css_selector='):
                ele = self.driver.find_elements_by_css_selector(loc[loc.find('=')+1:])
                # 目前暂不支持该种写法
                # ele = self.driver.find_elements_by_css_selector((#dataSourceName)[1])注意，如果使用这种方式应该是element不是elements
            else:
                ele = self.driver.find_elements_by_xpath(loc)
            # for el in ele:  # 得到的ele是列表中的对象元素
            #     self.driver.execute_script("arguments[0].style.background='#ff3bff'", el)#多个元素无法设置
        except Exception as e:
            self.log.info("定位元素出现异常，异常信息：{}".format(e))
        self.ele = ele
        return ele

    # 鼠标悬停
    def hover(self, loc=None):
        element = self.findEle(loc)
        ActionChains(self.driver).move_to_element(element).perform()

    def click(self, loc=None):
        ele = self.findEle(loc)
        # print("是否可见",ele.is_displayed())
        try:
            ele.click()
        except Exception as e:
            self.log.info("python点击异常，异常信息：{},正在使用js点击...".format(e))  # js有时可以点击页面遮挡住的元素，python定位不到js可以，比如下拉框选项看不到
            try:
                self.driver.execute_script("arguments[0].click();", ele)
            except Exception as e:
                self.log.info("js点击异常，异常信息：{}".format(e))

        '''
        针对重复识别验证码
        for i in range(1, 9):
            find_element(loc_type, loc_ex).click()
            try:
                sleep(5)
                find_element("xpath", '//*[text()="验证码错误"]')
            except:
                Logger().log().debug("输入验证码正确")
                break
            else:
                Logger().log().debug("验证码识别失败，第{}次重试".format(i))
                sleep(5)
                Logger().log().debug("清空验证码")
                find_element("xpath", '//*[@id="captcha_normal"]').clear()
                # 点击登录失败后自动刷新验证码，无需手动点击刷新
                # Logger().log().debug("点击更新验证码")
                # ActionChains(driver).move_to_element(find_element("id", "codeimage")).perform()
                # sleep(5)
                # find_element("id", "codeimage").click()
                # refresh_page()
                Logger().log().debug("识别验证码")
                iver = ivercode()
                Logger().log().debug("输入新的验证码")
                find_element("xpath", '//*[@id="captcha_normal"]').send_keys(iver)
                Logger().log().debug("点击登录")
                sleep(2)
                # find_element(loc_type, loc_ex).click()
                click(loc_type, loc_ex)
                sleep(2)
        '''

    def click_js(self, js):
        try:
            self.log.info("正在使用js定位并点击...")
            # js = "document.getElementsByClassName('ant-col-22')[0].firstChild.lastChild.firstChild.firstChild.firstChild.click();"
            self.driver.execute_script(js)
        except Exception as e:
            self.log.info("js定位并点击异常，异常信息：{}".format(e))

    # 鼠标键盘事件ActionChains
    # 鼠标点击,其他的查看
    def onclick(self, loc=None):
        '''
        :param loc: 需要点击的元素
        :return:
        '''
        # ele = self.findEle(loc)
        ActionChains(self.driver).click(
            WebDriverWait(self.driver, 10, 1).until(lambda el: self.findEle(loc), message="元素定位失败")).perform()

    # 双击
    def double_click(self, loc):
        ele = self.findEle(loc)
        ActionChains(self.driver).double_click(ele).perform()

    # 右击
    def right_click(self, loc):
        ele = self.findEle(loc)
        ActionChains(self.driver).context_click(ele).perform()

    # 拖曳元素
    def drag_ele(self, loc, x, y):
        # print("浏览器的窗口尺寸", self.driver.get_window_size(windowHandle='current'))
        ele = self.findEle(loc)
        width = self.driver.get_window_size(windowHandle='current')['width']
        width = self.driver.get_window_size(windowHandle='current')['width']*x
        height = self.driver.get_window_size(windowHandle='current')['height']*y
        # print("打印x", x, type(x))
        # print("打印y", y, type(y))
        # print("打印width",width)
        # print("打印height", height)
        #坐标跟尺寸不是一回事

        ActionChains(self.driver).drag_and_drop_by_offset(ele, width, height).perform()
        #拖动到另外一个元素drag_and_drop(initialPosition, targetPosition).perform()
        # 也可以一步一步click_and_hold(ele).move_by_offset(100,0).release().perform()
        # 宽度：通过js获取浏览器尺寸
        # var w = window.innerWidth | | document.documentElement.clientWidth | | document.body.clientWidth;
        # 高度：
        # var h = window.innerHeight | | document.documentElement.clientHeight | | document.body.clientHeight;

    # 拖动元素到另外一个元素
    def drag_ele_to_ele(self, loc, loc2):
        ele = self.findEle(loc)
        ele2 = self.findEle(loc2)
        # 可以通过获取元素的大小和坐标来确定鼠标移动到的位置
        # ele_size = self.findEle(loc).size
        # width = ele_size['width']
        # height = ele_size['height']
        ele_coordinate = self.findEle(loc).location
        print("打印位置",ele_coordinate)
        # 元素左上角横坐标
        x = ele_coordinate['x']
        print("打印x", x)
        # 元素左上角纵坐标
        y = ele_coordinate['y']
        import pyautogui
        # x, y = pyautogui.position()
        pyautogui.moveTo(x, y)
        # pyautogui.dragTo(x, y, button='left')  # 左键拖动
        sleep(2)
        # pyautogui.scroll(-50)
        # ActionChains(self.driver).drag_and_drop(ele, ele2).perform()#拖动到另外一个元素
        # 不能直接连过去，需要转折连，直接连过去不产生弹窗
        ActionChains(self.driver).click_and_hold(ele).move_to_element_with_offset(ele, 0, 100).move_to_element(ele2).release().perform()

    # 寻找多页列表中某个元素，用于寻找分页的元素
    def find_ele(self, loc, loc2):
        if self.findEle(loc) is None:
            ele = self.findEle(loc2)
            self.driver.execute_script("arguments[0].scrollIntoView();", ele)
            ele.click()
            self.find_ele(loc, loc2)
        else:
            pass

    # 输入事件
    def input(self, loc=None, value=None):

        ele = self.findEle(loc)
        try:
            # 注意，输入内容如果有换行符，会导致输入的内容不一致
            ele.send_keys(value)
        except Exception as e:
            self.log.info("python无法输入，错误信息为：{},正在使用js输入...".format(e))
            try:
                self.driver.execute_script("arguments[0].value='{}';".format(str(value)), ele)  # 该方法可以看到输入，但是可能系统识别不了，当成空值，还是无法提交(需要return)
            except Exception as e:
                self.log.info("使用js输入错误，错误信息为：{}".format(e))

    # 清空再输入
    def input_clear(self, loc=None, value=None):

        # ele = self.driver.find_elements(getattr(By, 'XPATH'), loc)[0]
        # ele = self.findEles(loc)[int(index)]目前已不需要这种方式
        # ele = self.findEles(loc)
        ele = self.findEle(loc)

        # for i in ele:
        #     print('每个元素{}'.format(i))
        # print("打印元素ele:{}和ele类型:{}".format(ele, type(ele)))

        try:
            # 方法二：通过键盘全选，然后直接输入新的内容，就不用clear了
            ele.send_keys(Keys.CONTROL, 'a')
            # ele.clear()
            # self.driver.execute_script("arguments[0].value=' ';", ele)
            # self.driver.execute_script("arguments[0].setAttribute('value', '{}');".format(str(value)), ele)

            # ActionChains(self.driver).double_click(ele).perform()
            sleep(1)
            # ele.click()#激活后又生成原来的数据，导致不清空
            ele.send_keys(str(value))
            sleep(5)
        except Exception as e:
            self.log.info("python无法输入，错误信息为：{}，正在使用js输入".format(e))
            self.driver.execute_script("arguments[0].value='{}';".format(str(value)), ele)  # 该方法可以看到输入，但是可能系统识别不了，当成空值，还是无法提交

    def update_ele(self, js):
        self.driver.execute_script(js)

    def input_js(self, loc=None, value=None):
        # 方式1：直接执行js
        # js = "document.getElementsByClassName('ant-col-22')[0].firstChild.lastChild.firstChild.firstChild.firstChild.value='文本'"
        # js = "document.getElementsByClassName('ant-col-22')[0].firstChild.lastChild.firstChild.firstChild.firstChild.setAttribute('id','newnewnew')"
        # new = self.driver.execute_script(js)
        # 方式2：修改属性后通过xpath,如当前
        # 方式3：通过xpath定位,js执行
        # self.driver.execute_script("arguments[0].value='好啊';", ele)
        # 异步执行代码，其他代码在执行
        # driver.execute_async_script('document.title')
        self.driver.execute_script(
            "document.getElementsByClassName('ant-col-22')[0].firstChild.lastChild.firstChild.firstChild.firstChild.setAttribute('id','dataSourceNameCreate')")
        ele = self.findEle(loc)
        try:
            ele.send_keys(str(value))
        except Exception as e:
            self.log.info("定位错误，错误信息:{}".format(e))

    # def sleep(self, value=None):
    #     self.driver.sleep(int(value))

    # 强制等待
    def sleep(self, time=None):
        # 可解决Message: element not interactable: element has zero size，有时必须用强制等待，其他等待不行
        sleep(int(time))

    def refresh(self):
        # 可以解决Element is not clickable at point问题
        self.driver.refresh()

    def quit(self):
        self.driver.quit()# driver.close() 关闭用户当前正在使用的 Web 浏览器窗口
        # self.on_press()

    def assert_text(self, value, expect):
        try:
            reality = self.findEle(value).text
            assert reality == expect
            self.log.info("流程正确，断言成功！")
            return True
        except Exception as e:
            self.log.info("流程正确，断言失败！失败信息：{}".format(e))
            return False

    def assert_url(self, expect):
        # self.driver.current_url  # 获取当前url
        # self.driver.page_source  # 获取页面源
        # self.driver.current_package  # 获取当前的包名
        # self.driver.current_activity  # 获取当前的activity
        # self.driver.current_context  # 列出当前上下文

        try:
            reality = self.driver.current_url
            assert reality == expect
            self.log.info("流程正确，断言成功！")
            return True
        except Exception as e:
            self.log.info("流程正确，断言失败！失败信息：{}".format(e))
            return False

    def assert_text_js(self, value, expect):
        try:
            element = WebDriverWait(self.driver, 10, 0.1).until(lambda el: self.findEle(value), '元素定位失败')
            reality = self.driver.execute_script("return arguments[0].innerHTML;", element)
            assert reality == expect
            self.log.info("流程正确，断言成功！")
            return True
        except Exception as e:
            self.log.info("流程正确，断言失败！失败信息：{}".format(e))
            return False

    # def get_web_data(self,**args):
    #     data1 = None
    #     data12 = None
    #     for i in data""
    #         args[data1]
    # 断言数据库数据
    def database_assert(self, sql, expect_data):
        import mysql.connector
        conn = mysql.connector.connect(host="222.186.32.112", user="hstech", password="pass@word1", database="hhks",
                                       port="3306")  # 暂未配置
        cur = conn.cursor()
        cur.execute(sql)
        columns = [i[0] for i in cur.description]
        expect_data_list = expect_data.split(',')
        if len(expect_data_list) == len(columns):
            expect_obj = {}
            # 如果需要校验多行数据，则跟下面一样
            for i in range(len(expect_data_list)):
                expect_obj[columns[i]] = str(expect_data_list[i])
            # for x in cur.description:
            #     print(x)# 得到的结果是：('goods_prize', 246, None, None, None, None, 1, 0)
            all_row = cur.fetchall()
            obj = {}
            obj_list = []
            # i = len(columns)
            for x in all_row:
                for i in range(len(columns)):
                    obj[columns[i]] = str(x[i])   # 如果需要既遍历列表元素也要元素的索引或者计数器，可以使用[[x,l.count(x)] for x in set(l)],让表元素改变数据类型[str(i) for i in a]
                obj_list.append(obj)
                obj = {}
            if expect_obj in obj_list:
                return True
            else:
                return False
        else:
            self.log.info("查询的列数与断言的数据不符，请重新填写！")
            return False

    def all_database_assert(self, db_type, sql, expect_data):
        if db_type == 'mysql':
            from config.config import host_mysql, user_mysql, password_mysql, database_mysql
            import mysql.connector
            conn = mysql.connector.connect(
                host=host_mysql,  # localhost
                user=user_mysql,  # root
                password=password_mysql,  # wxk111
                database=database_mysql,  # first
                # port=3306
            )
            cur = conn.cursor()
        elif db_type == 'oracle':
            # 需要匹配版本，切换到合适的python版本就会有
            import cx_Oracle
            from config.config import name_oracle, password_oracle, ip_oracle, port_oracle, serverName_oracle
            # conn = cx_Oracle.connect('name/password@ip:port/serverName')      # 连接数据库
            conn = cx_Oracle.connect(
                '{}/{}@{}:{}/{}'.format(name_oracle, password_oracle, ip_oracle, port_oracle, serverName_oracle))
            cur = conn.cursor()
        elif db_type == 'sqlserver':
            import pymssql
            from config.config import name_sqlserver,password_sqlserver,ip_sqlserver,port_sqlserver,database_sqlserver
            conn = pymssql.connect('{}:{}', '{}', '{}', '{}'.format(ip_sqlserver,port_sqlserver,name_sqlserver,password_sqlserver,database_sqlserver))  # 服务器名,账户,密码,数据库名)
            cur = conn.cursor()
        elif db_type == '达梦':
            import dmPython
            from config.config import user_dm,password_dm,server_dm,port_dm
            # connect = dmPython.connect(user="gpadmin", password="gpadmin", server="222.186.32.112", port="24532", autoCommit=True)
            r"""
            默认开启自动提交(autoCommit)模式
            """
            conn = dmPython.connect(user=user_dm, password=password_dm, server=server_dm,
                                         port=port_dm)  # user账号(对应模式名)
            cur = conn.cursor()
        elif db_type == 'greenplum':
            # 这类数据库选择表时必须加模式,比如：update gz_ods_schema.test_2 set id=8 where id=1
            # 也可以是python3-postgresql，参考：https://www.cnblogs.com/jmlovepython/p/5023794.html
            import psycopg2
            from config.config import database_greenplum,user_greenplum,password_greenplum,host_greenplum,port_greenplum
            conn = psycopg2.connect(database=database_greenplum, user=user_greenplum, password=password_greenplum, host=host_greenplum, port=port_greenplum)
            cur = conn.cursor()
        elif db_type == 'postgresql':
            # 这类数据库选择表时必须加模式,比如：update gz_ods_schema.test_2 set id=8 where id=1
            # 也可以是python3-postgresql，参考：https://www.cnblogs.com/jmlovepython/p/5023794.html
            import psycopg2
            from config.config import database_postgresql,user_postgresql,password_postgresql,host_postgresql,port_postgresql
            conn = psycopg2.connect(database=database_postgresql, user=user_postgresql, password=password_postgresql, host=host_postgresql, port=port_postgresql)
            cur = conn.cursor()


        # import mysql.connector
        # conn = mysql.connector.connect(host="222.186.32.112", user="hstech", password="pass@word1", database="hhks",
        #                                port="3306")  # 暂未配置
        # cur = conn.cursor()

        cur.execute(sql)
        columns = [i[0] for i in cur.description]
        # expect_data_list = expect_data.split(",")# split只会返回字符串列表，不会返回int
        try:
            expect_data_list = tuple(eval(expect_data))
        except Exception as e:
            print("打印出错误",e)
        if len(expect_data_list) == len(columns):
            expect_obj = {}
            # 如果需要校验多行数据，则跟下面数据库返回结果处理一样，列表中加对象
            for i in range(len(expect_data_list)):
                expect_obj[columns[i]] = expect_data_list[i]  #可以转换成字符串
            # for x in cur.description:
            #     print(x)# 得到的结果是：('goods_prize', 246, None, None, None, None, 1, 0)
            all_row = cur.fetchall()
            obj = {}
            obj_list = []
            # i = len(columns)
            for x in all_row:
                for i in range(len(columns)):
                    obj[columns[i]] = x[i]   #可以转换成字符串 # 如果需要既遍历列表元素也要元素的索引或者计数器，可以使用[[x,l.count(x)] for x in set(l)],让表元素改变数据类型[str(i) for i in a]
                obj_list.append(obj)
                obj = {}
            if expect_obj in obj_list:
                self.log.info("数据库断言成功")
                return True
            else:
                self.log.info("数据库断言失败")
                return False
        else:
            self.log.info("查询的列数与断言的数据不符，请重新填写！")
            return False

    # 断言列表中是否存在某个元素
    def listdata_assert(self, loc, expect):
        try:
            eles = self.findEles(loc)
            reality = []
            for i in eles:
                reality.append(i.text)
            assert expect in reality
            self.log.info("流程正确，断言成功！")
            return True
        except Exception as e:
            self.log.info("流程正确，断言失败！失败信息：{}".format(e))
            return False





    # unittest断言函数
    def get_element(self, loc_type, value):
        return self.driver.find_element(getattr(By, loc_type.upper()), value).text

    def verify(self, value):
        assert value in self.driver.page_source  # 验证当前页面中是否含有value，暂不使用

    # 断言数据库数据，一般不用
    def mysql_assert_text(self, sql, expect):

        try:
            self.cmd.execute(sql)
            reality = self.cmd.fetchall()
            # [(1, '语文', 1), (2, '数学', 2)]
            # print('得到结果集:{}'.format(reality))
            '''
            #当数据量大的时候会出现性能问题，所以建议使用for循环一行行读取数据 注意：cur.fetchone()返回None是因为遍历过数据后,cur.rowcount()需要遍历过数据后才会显示正确的行数
            for i in range(1,self.cmd.rowcount):
                row = self.cmd.fetchone()
                if row[0][0] == expect:
                    print("断言成功")
                    break
                else:
                    print("断言失败")
            '''
            reality = reality[0][0]
            reality = str(reality)
            self.log.info('查询到的reality:{}'.format(reality))
            '''
            使用正则取数据
            import re
            reality = str(reality)
            reality = re.findall('[\d\.\d]',reality)
            return reality
            '''
            self.log.info("返回的数据：{}".format(reality))
            assert reality == expect
            self.log.info("流程正确，断言成功！")
            return True
        except Exception as e:
            # self.log.exception("流程正确，断言失败！失败信息：{}".format(e))
            self.log.info("流程正确，断言失败！失败信息：{}".format(e))
            return False

    def allure_screenshot(self, expect, actual):
        try:
            assert expect == actual
        except AssertionError as e:
            # self.driver.save_screenshot()
            import allure
            screenshot = self.driver.get_screenshot_as_png()
            allure.attach(screenshot, "错误截图的名称", allure.attachment_type.PNG)
            raise e

    def verify_code(self):
        ele = self.driver.find_element_by_id("codeimage")
        ele.screenshot("../files/verify.png")
        headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }
        data = {
            'user': 'wuqingfqng',
            'pass2': '6e8ebd2e301f3d5331e1e230ff3f3ca5',  # 密碼：wuqing&fqng
            "softid": "904357",
            "codetype": "1902"
        }
        userfile = open("../files/verify.png", "rb").read()
        userfile = {"userfile": ("./files/verify.png", userfile)}
        res = requests.post("http://upload.chaojiying.net/Upload/Processing.php", data=data, files=userfile,
                            headers=headers)
        res = res.json()
        vercode = res["pic_str"]
        vercode = vercode[:4]
        return vercode

    # 滑块验证码
    def slid_code(self, slider_ele, background_ele, btn, expect_ele):
        '''

        :param slider_ele: 滑块图片的位置
        :param background_ele: 背景图片的位置
        :param btn: 滑块元素位置
        :param expect_ele: 期望元素位置
        :return:
        '''
        while True:
            # 第六步：滑动验证码
            # 6.1创建一个滑动验证的对象
            sli = SlideVerificationCode()
            # 6.2 计算滑动的距离

            # 切换到验证码所在的iframe(如果需要)
            # driver.switch_to.frame(driver.find_element_by_xpath('//*[@id="tcaptcha_iframe"]'))

            # 定位滑块图片
            slider_ele = self.driver.find_element_by_xpath(slider_ele)
            # 定位验证码背景图
            background_ele = self.driver.find_element_by_xpath(background_ele)

            distance = sli.get_element_slide_distance(slider_ele, background_ele)
            # print("滑动的距离为：", distance)
            # 根据页面图片缩放比调整滑动距离,目前写死这些数据
            distance = distance * 280 / 680 - 31  # 680是原始宽度，280是在页面上的宽度，distance是按原始的，31为滑块距离左边的距离（电脑缩放比100%为标准）
            # 6.3模拟滑动鼠标
            btn = self.driver.find_element_by_xpath(btn)
            sli.slide_verification(self.driver, btn, distance)
            # // *[ @ id = "e_reload"]
            try:
                sleep(5)
                self.driver.find_element_by_xpath(expect_ele).click()
                sleep(5)
            except:
                sleep(5)
                break

    # driver对象设置项，只需设置一次，driver整个生命周期有效，在页面加载完成后调用，即浏览器在转圈完成后才开始算时间，与显示等待的区别
    def implicit_wait(self, time):
        self.driver.implicitly_wait(time)

    # 显示等待定位元素
    def display_wait(self, timeout=10, frequency=0.5, loc=''):
        '''
        如果定位成功会返回元素对象,util是查找元素是否存在，until not是查找元素是否不存在，成功就会返回元素对象，不成功就会报message错误
        :param timeout: 最大时间
        :param frequency: 频率
        :param loc: 位置
        :return:
        '''
        # frequency = frequency.astype(str)
        wait = WebDriverWait(self.driver, int(timeout), int(frequency))
        return wait.until(lambda el: self.findEle(loc), message="显示等待时，元素定位失败")

        # wait = WebDriverWait(self.driver, int(timeout), int(frequency))
        # ele = wait.until(lambda el: self.findEle(loc), message="元素定位失败")
        # try:
        #     ele.click()
        # except Exception as e:
        #     print("发生错误{}".format(e))

    # 切换至新窗体 driver.switch_to.new_window('tab')可以省略切换窗体，省略步骤
    def switch_to_new_current(self):
        handles = self.driver.window_handles
        self.driver.switch_to.window(handles[1])

    # 切换至最新打开的窗体
    def switch_to_newest_current(self):
        handles = self.driver.window_handles
        # print(f"打印句柄:{handles}")
        self.driver.switch_to.window(handles[-1])

    # 关闭旧窗体
    def close_old_current(self):
        self.driver.close()

    # 切换至旧窗体
    def switch_to_old_current(self):
        handles = self.driver.window_handles
        self.driver.switch_to.window(handles[0])

    # 切换至新窗体，并关闭旧窗体
    def switch_and_close(self):
        handles = self.driver.window_handles
        self.driver.close()
        self.driver.switch_to.window(handles[1])

    # 切换至Iframe窗体
    def switch_to_iframe(self, value):
        self.driver.switch_to.frame(self.findEle(value))

    # 进入iframe
    def intoIframe(self, loc):
        ele = self.findEle(loc)
        # self.driver.switch_to_frame(ele)这是旧版
        self.driver.switch_to.frame(ele)

    # 切换回默认窗体
    def switch_to_default(self):
        self.driver.switch_to.default_content()

    # 上传文件（PC端）
    def upload_files(self, file_path, file, *args):
        import pywinauto
        from pywinauto.keyboard import send_keys
        app = pywinauto.Desktop()
        # 选中打开窗口
        dlg = app["打开"]
        # 打印窗口上所有控件，不使用定位工具
        dlg.print_control_identifiers()
        dlg["Toolbar3"].click()
        send_keys(file_path)
        #回车
        send_keys("{VK_RETURN}")
        dlg["文件名(&N):Edit"].type_keys('"{}"'.format(file))  # 普通发票.jpg,传单个文件可以减少1个引号
        sleep(3)
        #上传多个文件
        for i in args:
            send_keys('"{}"'.format(i))
        #点击打开
        sleep(3)
        dlg["打开(&O)"].click()

    # 接口上传文件，还有文件下载：http://www.45fan.com/article.php?aid=1CWDIJRgpU1Il1lX
    def send_file(self):
        url = "http://httpbin.org/post"
        data = ""
        # 这种写法一个key可以传多个文件，这个key就是images，如果使用同一个参数，那就用这种写法
        #支持各种文件类型doc, docx, txt, pdf, png, gif, jpg, jpeg, tiff, html, rtf, xls, txt（不一定要匹配，比如ppt用txt也行）
        files = [
            ('images', ('images.jpg', open('./img/timg.jpg', 'rb'), 'image/png')),
            ('images', ('images2.jpg', open('./img/ti.jpg', 'rb'), 'image/png'))
        ]
        # # 其他写法2
        # # fiels为字典类型数据，上传的文件为键值对的形式，参数名作为键，
        # # 参数值是一个元组，内容为以下格式（文件名，打开的文件流，文件类型）
        # files = {
        #     "pic": ("test01.gif", open("test01.gif", "rb"), "images/git")
        # }
        # # 注意点：除了上传的文件，接口其他参数不能放入files中
        # # 其他写法3，上传多个文件
        # files = {
        #     "api_field1": ("file_name", open("file_path", "rb")),
        #     "api_field2": ("file_name", open("file_path", "rb"), "image/jpeg"),
        #     "api_field3": ("file_name", open("file_path", "rb"), "image/jpeg", {"header-param": "xxx"})
        # }
        # # 其他写法4，可以将json数据放到file文件上传中
        # json_content = {"key1": "value1", "key2": "value2"}
        # files = {
        #     'json': (None, json.dumps(json_content, ensure_ascii=False), 'application/json'),
        #     'file': (os.path.basename(file), open(file, 'rb'), 'application/octet-stream')
        # }
        # # 其他写法5
        # files = {'a.xlsx': open('../file/a.xlsx', 'rb')}

        res = requests.post(url=url, files=files)
        print(res.text)


    # 缩放窗口
    def zoom_window(self):
        self.driver.set_window_size(500, 500)

    # 缩放页面,可能会导致Message: move target out of bounds可能是因为缩小了页面导致的，需要取消缩放页面并且最大化窗口解决或者使用js，如果是鼠标键盘操作只能去掉缩放页面
    def zoom_page(self):
        self.driver.execute_script("document.body.style.zoom='0.67'")

    # 滚动到指定元素,这里是相对于整个windows或者document的，对下拉框滚动条无效（对下拉框滚动条依然有效）
    def scroll_to_ele(self, loc):
        element = self.findEle(loc)
        self.driver.execute_script("arguments[0].scrollIntoView();", element)#scrollIntoView(false)为向上滑动
        # document.scrollingElement.scrollTop表示上下滚动，0-2000区间，也可以document.scrollingElement.scrollTop=400
        # window.scrollTo(x,y)左右滚动（不一定）

    # 让页面滚动到元素位置，暂时不用
    def scroll_to_ele2(self, loc, index):
        # self.driver.execute_script("scrollingElement.scrollTop = 1")
        # from selenium.webdriver.support.select import Select
        # select = Select(self.driver.find_element_by_xpath(loc))
        # select.select_by_visible_text('tm的greenplum')
        ele = self.driver.find_elements_by_css_selector(loc)[int(index)]
        self.driver.execute_script("arguments[0].style.background='33ccff'", ele)
        sleep(10)
        # ele = self.findEle(loc)
        ele_new = self.driver.find_element_by_xpath('//*[@id="rc-tabs-0-panel-noRelate"]/div/div[2]/div/div[2]/div/div/div[2]/div[2]/form/div[2]/div[2]/div/div[2]/div/div/div')
        ActionChains(self.driver).click_and_hold(ele).move_to_element_with_offset(ele_new, 0, 10).perform()

    # 下拉选择框
    def select(self, scrollbar_loc, list_loc, text):
        # 选择框中，当元素不可见时（看得到但是定位不到），无法通过滚动到该元素，只能通过设置display:black,如果有滚动条，设置可见后，可能只显示10个
        # 设置可见
        # ele = self.driver.find_element_by_xpath('/html/body/div[3]/div/div')
        # self.driver.execute_script("arguments[0].setAttribute('display','block')", ele)
        # 定位到滚动条
        # ele = self.driver.find_elements_by_css_selector('.rc-virtual-list-scrollbar-thumb')[1]
        try:
            ele = self.findEle(scrollbar_loc)
        except Exception as e:
            self.log.info("定位滚动条元素出错，错误信息为{}".format(e))
        self.driver.execute_script("arguments[0].style.background='33ccff'", ele)
        sleep(1)
        # ele = self.findEle(loc)
        # ele_new = self.driver.find_element_by_xpath(
        #     '//*[@id="rc-tabs-0-panel-noRelate"]/div/div[2]/div/div[2]/div/div/div[2]/div[2]/form/div[2]/div[2]/div/div[2]/div/div/div')
        ActionChains(self.driver).drag_and_drop_by_offset(ele, 0, 10).perform()

        try:
            eles = self.findEles(list_loc)
        except Exception as e:
            self.log.info("定位下拉列表元素集出错，错误信息为{}".format(e))
        # eles = self.driver.find_elements_by_css_selector('.rc-virtual-list-holder-inner')[1]
        status = False
        for i in eles:
            if text == i.text:
            # if text in i.text:
                # print([i.text for i in eles])
                i.click()
                status = True
                break
        if status == False:
            ActionChains(self.driver).drag_and_drop_by_offset(ele, 0, 10).perform()
            self.select(scrollbar_loc, list_loc, text)

    # 滚动到下拉框需要选中的元素，针对多级和打开无滚动条下拉框,与mouse_to_select_and_scroll结合使用
    def select_scroll_loc(self, scrollbar_loc, list_loc, text):
        # 选择框中，当元素不可见时（看得到但是定位不到），无法通过滚动到该元素，只能通过设置display:black,如果有滚动条，设置可见后，可能只显示10个
        # 设置可见
        # ele = self.driver.find_element_by_xpath('/html/body/div[3]/div/div')
        # self.driver.execute_script("arguments[0].setAttribute('display','block')", ele)
        # 定位到滚动条
        # ele = self.driver.find_elements_by_css_selector('.rc-virtual-list-scrollbar-thumb')[1]

        # self.driver.execute_script('document.scrollingElement.scrollTop||document.body.scrollTop;')
        # self.driver.execute_script('window.scrollTo(0,20)')
        try:
            ele = self.findEle(scrollbar_loc)
        except Exception as e:
            print("无法找到滚动条")

        self.driver.execute_script("arguments[0].style.background='33ccff'", ele)


        # ele = self.findEle(loc)
        # ele_new = self.driver.find_element_by_xpath(
        #     '//*[@id="rc-tabs-0-panel-noRelate"]/div/div[2]/div/div[2]/div/div/div[2]/div[2]/form/div[2]/div[2]/div/div[2]/div/div/div')
        ActionChains(self.driver).drag_and_drop_by_offset(ele, 0, 10).perform()

        eles = self.findEles(list_loc)
        # eles = self.driver.find_elements_by_css_selector('.rc-virtual-list-holder-inner')[1]
        print(f"打印出元素{eles}")
        status = False
        for i in eles:
            if text == i.text:
                # if text in i.text:
                # print([i.text for i in eles])
                # i.click()
                status = True
                break
        if status == False:
            ActionChains(self.driver).drag_and_drop_by_offset(ele, 0, 10).perform()
            self.select_scroll_loc(scrollbar_loc, list_loc, text)

    def checkbox(self, loc):
        eles = self.findEles(loc)

        for ele in eles:
            if ele.is_selected():
                pass
            else:
                ele.click()

    # def uncheck(self, loc):
    #     eles = self.findEles(loc)
    #     for ele in eles:
    #         if ele.is_selected() and ele.get_attribute('checked'):
    #             ele.click()
    #         else:
    #             pass


    def mouse_enter(self):
        # 可以通过获取元素的大小和坐标来确定鼠标移动到的位置
        # ele_size = self.driver.find_element_by_xpath('').size
        # width = ele_size['width']
        # height = ele_size['height']
        # ele_coordinate = self.driver.find_element_by_xpath('').location
        # # 元素左上角横坐标
        # x = ele_coordinate['x']
        # # 元素左上角纵坐标
        # y = ele_coordinate['y']
        import pyautogui
        x,y = pyautogui.position()
        print("hh",x,y)
        pyautogui.moveTo(1335, 479)
        # print("打印鼠标位置",x,y)
        pyautogui.scroll(-50)

    # 鼠标移动到下拉框并滚动下拉框
    def mouse_to_select_and_scroll(self, ele_coordinate, scroll_len):
        # 可以通过获取元素的大小和坐标来确定鼠标移动到的位置
        # ele_size = self.driver.find_element_by_xpath('').size
        # width = ele_size['width']
        # height = ele_size['height']
        # ele_coordinate = self.driver.find_element_by_xpath('').location
        # # 元素左上角横坐标
        # x = ele_coordinate['x']
        # # 元素左上角纵坐标
        # y = ele_coordinate['y']
        ele_coordinate = tuple(eval(ele_coordinate))
        x = ele_coordinate[0]
        y = ele_coordinate[1]
        import pyautogui
        # x,y = pyautogui.position()
        pyautogui.moveTo(x, y)
        # print("打印鼠标位置",x,y)
        pyautogui.scroll(scroll_len)  # 负数向下

    #删除属性
    def rm_attribute_js(self, loc):
        element = self.findEle(loc)
        # self.driver.execute_script("argument[0],removeAttribute('name');", element)  # 目前写死为移除name属性
        self.driver.execute_script("argument[0],removeAttribute('name');", element)  # 目前写死为移除name属性

    # Alert，显示通知消息，目的是通知用户某个信息，需要用户点击确定
    def alert(self):
        # driver.switch_to.alert/webdriver.switch_to.alert
        sleep(2)
        # self.driver.switch_to_alert().accept()
        # self.driver.switch_alert.accept()
        self.driver.switch_to.alert.accept()



if __name__ == '__main__':
    Web().upload_files(r"C:\Users\wxk\Desktop\不同大小的文件", "新建XLS工作表.xls", "loginData.xlsx")